package cn.qianxun.meta.common.log.changeField.aspect;


import cn.qianxun.meta.common.core.utils.SpringUtils;
import cn.qianxun.meta.common.log.changeField.annotation.ChangeLog;
import cn.qianxun.meta.common.log.changeField.annotation.CompareField;
import cn.qianxun.meta.common.log.changeField.util.ObjectComparatorUtil;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import cn.qianxun.meta.common.core.utils.string.StringUtils;
import cn.qianxun.meta.common.log.changeField.util.ContentParser;
import cn.qianxun.meta.common.log.changeField.util.ReflectionUtils;
import cn.qianxun.meta.common.log.changeField.vo.ChangeFieldValueVO;
import cn.qianxun.meta.common.log.event.ChangeFieldValueLogEvent;
import cn.qianxun.meta.common.satoken.utils.LoginHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;

/**
 * @Author fuzhilin
 * @Date 2023/9/5 10:06
 * @Description
 */
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class ChangeLogAspect {
    private final ApplicationContext applicationContext;


    // 环绕通知
    @Before("@annotation(changeLog)")
    public void around(JoinPoint joinPoint, ChangeLog changeLog) {
        try {
            Object[] args = joinPoint.getArgs();
            Object newObject = args[0];
            Object oldObject = null;
            try {
                ContentParser contentParser = (ContentParser) applicationContext.getBean(changeLog.parseclass());
                oldObject = contentParser.getResult(joinPoint, changeLog);
            } catch (Exception e) {
                log.error("service加载失败:", e);
                e.printStackTrace();
            }
            if (StringUtils.isNotNull(oldObject)) {
                String idName = "id";
                if (!"id".equals(changeLog.idName())) {
                    idName = changeLog.idName();
                }
                Field field = oldObject.getClass().getDeclaredField(idName);
                field.setAccessible(true);
                String id = String.valueOf(field.get(oldObject));
                List<ChangeFieldValueVO> fieldValueList = ObjectComparatorUtil.compare(id, changeLog.moduleName(), LoginHelper.getUserName(), oldObject, newObject);
                if (!CollectionUtils.isEmpty(fieldValueList)) {
                    // 发布事件保存数据库
                    SpringUtils.context().publishEvent(new ChangeFieldValueLogEvent().setFieldValueList(fieldValueList));
                }
            } else {
                log.error("oldObject为空");
            }
        } catch (Exception e) {
            log.error("字段值变化计算失败");
            e.printStackTrace();
        }
    }

    private String defaultDealUpdate(Object newObject, Map<String, Object> oldMap) {
        try {
            Map<String, Object> newMap = (Map<String, Object>) objectToMap(newObject);
            StringBuilder str = new StringBuilder();
            Object finalNewObject = newObject;
            oldMap.forEach((k, v) -> {
                Object newResult = newMap.get(k);
                if (null != v && !v.equals(newResult)) {
                    Field field = ReflectionUtils.getAccessibleField(finalNewObject, k);
                    CompareField dataName = field.getAnnotation(CompareField.class);
                    if (null != dataName) {
                        str.append(dataName.value()).append(",").append("旧值为：").append(v).append(",").append("新值为：").append(newResult).append("。\n");
                    } else {
                        str.append(field.getName()).append(",").append("旧值为：").append(v).append(",").append("新值为：").append(newResult).append("。\n");
                    }
                }
            });
            return str.toString();
        } catch (Exception e) {
            log.error("比较异常", e);
            throw new RuntimeException("比较异常", e);
        }
    }

    private Map<?, ?> objectToMap(Object obj) {
        if (obj == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 如果使用JPA请自己打开这条配置
        // mapper.addMixIn(Object.class, IgnoreHibernatePropertiesInJackson.class);
        Map<?, ?> mappedObject = mapper.convertValue(obj, Map.class);
        return mappedObject;
    }

}
